package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

func main() {
	//wg := sync.WaitGroup{}
	var wg sync.WaitGroup
	dogch, catch, fishch := make(chan struct{}), make(chan struct{}), make(chan struct{})
	var dogcounter, catcounter, fishcounter uint32

	wg.Add(3)
	go printdog(&wg, dogcounter, dogch, catch)
	go printcat(&wg, catcounter, catch, fishch)
	go printfish(&wg, fishcounter, fishch, dogch)

	dogch <- struct{}{}
	wg.Wait()
}

func printdog(wg *sync.WaitGroup, counter uint32, dogch, catch chan struct{}) {
	//defer close(dogch)
	for {
		if counter >= uint32(10) {
			wg.Done()
			return
		}
		<-dogch

		fmt.Println("dog")
		atomic.AddUint32(&counter, 1)

		catch <- struct{}{}
	}
}

func printcat(wg *sync.WaitGroup, counter uint32, catch, fishch chan struct{}) {
	//defer close(catch)
	for {
		if counter >= uint32(10) {
			wg.Done()
			return
		}
		<-catch

		fmt.Println("cat")
		atomic.AddUint32(&counter, 1)

		fishch <- struct{}{}
	}
}

func printfish(wg *sync.WaitGroup, counter uint32, fishch, dogch chan struct{}) {
	//defer close(fishch)
	for {
		if counter >= uint32(10) {
			wg.Done()
			return
		}
		<-fishch

		fmt.Println("fish")
		atomic.AddUint32(&counter, 1)

		dogch <- struct{}{}
	}
}
